import {MetricsRegisterExtra} from "@lodestar/utils";
import {RequestErrorCode} from "./request/errors.js";

export type Metrics = ReturnType<typeof getMetrics>;

/**
 * A collection of metrics used throughout the Gossipsub behaviour.
 */
export function getMetrics(register: MetricsRegisterExtra) {
  // Using function style instead of class to prevent having to re-declare all MetricsPrometheus types.

  return {
    outgoingRequests: register.gauge<{method: string}>({
      name: "beacon_reqresp_outgoing_requests_total",
      help: "Counts total requests done per method",
      labelNames: ["method"],
    }),
    outgoingOpenedStreams: register.counter<{method: string}>({
      name: "beacon_reqresp_outgoing_opened_streams_total",
      help: "Counts total opened streams per method",
      labelNames: ["method"],
    }),
    outgoingClosedStreams: register.counter<{method: string}>({
      name: "beacon_reqresp_outgoing_closed_streams_total",
      help: "Counts total closed streams per method",
      labelNames: ["method"],
    }),
    outgoingRequestRoundtripTime: register.histogram<{method: string}>({
      name: "beacon_reqresp_outgoing_request_roundtrip_time_seconds",
      help: "Histogram of outgoing requests round-trip time",
      labelNames: ["method"],
      // Spec sets RESP_TIMEOUT = 10 sec
      buckets: [0.1, 0.2, 0.5, 1, 5, 10, 15, 60],
    }),
    outgoingErrors: register.gauge<{method: string}>({
      name: "beacon_reqresp_outgoing_requests_error_total",
      help: "Counts total failed requests done per method",
      labelNames: ["method"],
    }),
    outgoingErrorReasons: register.gauge<{reason: RequestErrorCode}>({
      name: "beacon_reqresp_outgoing_requests_error_reason_total",
      help: "Count total outgoing request errors by reason",
      labelNames: ["reason"],
    }),
    incomingRequests: register.gauge<{method: string}>({
      name: "beacon_reqresp_incoming_requests_total",
      help: "Counts total responses handled per method",
      labelNames: ["method"],
    }),
    incomingOpenedStreams: register.counter<{method: string}>({
      name: "beacon_reqresp_incoming_opened_streams_total",
      help: "Counts total incoming opened streams per method",
      labelNames: ["method"],
    }),
    incomingClosedStreams: register.counter<{method: string}>({
      name: "beacon_reqresp_incoming_closed_streams_total",
      help: "Counts total incoming closed streams per method",
      labelNames: ["method"],
    }),
    incomingRequestHandlerTime: register.histogram<{method: string}>({
      name: "beacon_reqresp_incoming_request_handler_time_seconds",
      help: "Histogram of incoming requests internal handling time",
      labelNames: ["method"],
      // Spec sets RESP_TIMEOUT = 10 sec
      buckets: [0.1, 0.2, 0.5, 1, 5, 10],
    }),
    incomingErrors: register.gauge<{method: string}>({
      name: "beacon_reqresp_incoming_requests_error_total",
      help: "Counts total failed responses handled per method",
      labelNames: ["method"],
    }),
    outgoingResponseTTFB: register.histogram<{method: string}>({
      name: "beacon_reqresp_outgoing_response_ttfb_seconds",
      help: "Time to first byte (TTFB) for outgoing responses",
      labelNames: ["method"],
      // Spec sets TTFB_TIMEOUT = 5 sec
      buckets: [0.1, 1, 5],
    }),
    incomingResponseTTFB: register.histogram<{method: string}>({
      name: "beacon_reqresp_incoming_response_ttfb_seconds",
      help: "Time to first byte (TTFB) for incoming responses",
      labelNames: ["method"],
      // Spec sets TTFB_TIMEOUT = 5 sec
      buckets: [0.1, 1, 5],
    }),
    dialErrors: register.gauge({
      name: "beacon_reqresp_dial_errors_total",
      help: "Count total dial errors",
    }),
    selfRateLimiterPeerCount: register.gauge({
      name: "beacon_reqresp_self_rate_limiter_peer_count",
      help: "Count of peers tracked by the self rate limiter",
    }),
  };
}
